﻿/*++ BUILD Version: 0001    // Increment this if a change has global effects

Copyright (c).  All rights reserved.

Module Name:

        MemLeak.h 

Abstract:

        内存泄漏检测, 只在DEBUG编译版本下有效.

Author:lzlong

Revision History:

--*/

#ifndef _MEMLEAK_H_H_
#define _MEMLEAK_H_H_
#include <Windows.h>
#include <map>
#include <DbgHelp.h>
#include <string>

#undef InitMemLeak
#undef UninitMemLeak

#ifdef _DEBUG
#define InitMemLeak() CMemLeak::Instance().Init();
#define UninitMemLeak() CMemLeak::Instance().Uninit();
#else
#define InitMemLeak() ((void)0)
#define UninitMemLeak() ((void)0)
#endif

#ifdef _DEBUG

class CInitMemLeak
{
public:
    CInitMemLeak(bool bShowOperateDlg = true);
    ~CInitMemLeak();
};

struct STACKFRAMEENTRY {
    ADDRESS    addrPC;
    ADDRESS    addrFrame;
};

#define MLD_MAX_TRACEINFO            63
typedef struct tagAllocBlockInfo {
    //Added constructor to zero memory - thanks to bugfix from OfekSH.
    tagAllocBlockInfo() {
        ZeroMemory(fileName, sizeof(fileName));
        ZeroMemory(traceinfo, sizeof(traceinfo));
    }
    bool                bMarkedReported;
    void*                address;
    size_t                size;
    TCHAR                fileName[MAX_PATH];
    DWORD                lineNumber;
    DWORD                occurance;
    STACKFRAMEENTRY        traceinfo[MLD_MAX_TRACEINFO];
} AllocBlockInfo;

typedef struct tagAllocTotalInfo {
    tagAllocTotalInfo(){
        dwTotalsize = 0;
        dwAllocTimes = 0;
        PcOffset = 0;
    }
    tagAllocTotalInfo(const DWORD alloctimes, const __int64 offset, DWORD totalsize, const std::string& _strStack){
        strStack = _strStack;
        dwAllocTimes = alloctimes;
        PcOffset = offset;
        dwTotalsize = totalsize;
    }
    std::string strStack;
    DWORD dwTotalsize;
    DWORD dwAllocTimes;
    __int64 PcOffset;
} AllocTotalInfo;

class CMemLeak 
{
public:
    CMemLeak();
    virtual ~CMemLeak();

    static CMemLeak& Instance() {
        static CMemLeak ml;
        return ml;
    }

    void Init();
    void Uninit();

    void ClearMemStatistics();
    void dumpCurrentMemoryTrace(int iSnapLoopTime = 0);
    void dumpCurrentVirtualAllocTrace();
    void VirtualAllocCallsTrace(LPVOID lpAllocAddr, DWORD dwSize);
    void VirtualFreeCallsTrace(LPVOID lpAllocAddr);

private:
    BOOL InitSymInfo (
        __in_opt TCHAR* lpszUserSymbolPath = NULL
        );

    BOOL symFunctionInfoFromAddresses (
        __in ULONG_PTR fnAddress, 
        __in ULONG_PTR stackAddress, 
        __out_ecount(dwSymbolSize) TCHAR* lpszSymbol,
        __in DWORD dwSymbolSize
        );
    BOOL symModuleNameFromAddress (
        __in ULONG_PTR address, 
        __out_ecount(dwModuleSize) TCHAR* lpszModule, 
        __in DWORD dwModuleSize
        );
    BOOL symSourceInfoFromAddress(
        __in ULONG_PTR address, 
        __out_ecount(dwSourceInfoSize) TCHAR* lpszSourceInfo, 
        __in DWORD dwSourceInfoSize
        );
    BOOL symStackTrace (
        __out STACKFRAMEENTRY* pStacktrace
        );

    void dumpMemoryTrace();

private:
    static int __cdecl MemoryAllocHook (
        int    allocType, 
        void    *userData, 
        size_t size, 
        int    blockType, 
        long    requestNumber, 
        const unsigned char    *filename,
        int    lineNumber
        );
    static void DeleteOldTempFiles (
        const TCHAR* dir, 
        const TCHAR* type, 
        int days
        );

public:
    volatile bool m_bMapClearing = false;
    std::map<PVOID, AllocBlockInfo> m_mapAllInfo;
    std::map<PVOID, AllocBlockInfo> m_mapAllInfoClearing;
    std::map<PVOID, AllocBlockInfo> m_mapAllVitualAllocBlockInfo;
    
    int                                m_VirtualAllocIoccurance;
private:
    DWORD m_dwOccurance;
    volatile bool m_bSelfAlloc;
    volatile bool m_bLoopAlloc;  // 短时间内不要统计新的开辟  留个开辟的空间释放的时间

    _CRT_ALLOC_HOOK m_pfnOldCrtAllocHook;    

    typedef USHORT 
        (WINAPI *CaptureStackBackTraceType) (
        __in ULONG, 
        __in ULONG, 
        __out PVOID*, 
        __out_opt PULONG
        );
    CaptureStackBackTraceType m_fnRtlCaptureStackBackTrace;
};

#endif // _DEBUG

#endif // _MEMLEAK_H_H_